var ctxCL;
var cmdQueue;
var localWS;
var globalWS;
var bufSize;
var bufXYZ;
var bufXVel;
var bufYAccel;
var bufYDecel;
var bufZVel;
var bufRandom;
var vectorLength;
var kernel;

function InitCL() 
{
	if (window.WebCL == undefined) {
		alert("Unfortunately your system does not support WebCL. " +
          "Make sure that you have both the OpenCL driver " +
          "and the WebCL browser extension installed.");
		return false;
	}
	
	var platforms;
	var devices;
	try {
		platforms = WebCL.getPlatformIDs();
		devices = [];
		for (var i in platforms) {
			var plat = platforms[i];
			devices[i] = plat.getDeviceIDs(WebCL.CL_DEVICE_TYPE_GPU);
		}
	} catch (e) {
		alert("Unfortunately platform or device inquiry failed.");
		return false;
	}
	
	ctxCL = WebCL.createContextFromType( [WebCL.CL_CONTEXT_PLATFORM, platforms[0]], WebCL.CL_DEVICE_TYPE_GPU);
	vectorLength = particles.length;
	bufSize = Float32Array.BYTES_PER_ELEMENT * vectorLength;
	bufXYZ = ctxCL.createBuffer( WebCL.CL_MEM_READ_WRITE, bufSize * 4 );
	bufXVel = ctxCL.createBuffer( WebCL.CL_MEM_READ_WRITE, bufSize );
	bufYAccel = ctxCL.createBuffer( WebCL.CL_MEM_READ_WRITE, bufSize );
	bufYDecel = ctxCL.createBuffer( WebCL.CL_MEM_READ_WRITE, bufSize );
	bufZVel = ctxCL.createBuffer( WebCL.CL_MEM_READ_WRITE, bufSize );
	bufRandom = ctxCL.createBuffer( WebCL.CL_MEM_WRITE, bufSize );
	
	var kernelSrc = loadKernel("clProgramParticleFountain");
	var program = ctxCL.createProgramWithSource(kernelSrc);
	var devices2 = ctxCL.getContextInfo(WebCL.CL_CONTEXT_DEVICES);
	
	try {
		program.buildProgram([devices2[0]], "");
	} catch(e) {
		alert ("Failed to build WebCL program. Error "
             + program.getProgramBuildInfo (devices2[0], WebCL.CL_PROGRAM_BUILD_STATUS)
             + ":  " 
             + program.getProgramBuildInfo (devices2[0], WebCL.CL_PROGRAM_BUILD_LOG));
		return false;
	}
	
	kernel = program.createKernel("ckParticleFountain");
	kernel.setKernelArg(0, bufXYZ);
	kernel.setKernelArg(1, bufXVel);
	kernel.setKernelArg(2, bufYAccel);
	kernel.setKernelArg(3, bufYDecel);
	kernel.setKernelArg(4, bufZVel);
	kernel.setKernelArg(5, bufRandom);
	
	//Init ND-range
	globalWS = [Math.ceil (vectorLength / LOCAL_WS) * LOCAL_WS];
	
	cmdQueue = ctxCL.createCommandQueue (devices2[0], 0);
	cmdQueue.enqueueWriteBuffer (bufXVel, false, 0, bufSize, XVelArray, []);
	cmdQueue.enqueueWriteBuffer (bufZVel, false, 0, bufSize, ZVelArray, []);
	cmdQueue.enqueueWriteBuffer (bufYAccel, false, 0, bufSize, AccelArray, []);
	cmdQueue.enqueueWriteBuffer (bufYDecel, false, 0, bufSize, DecelArray, []);
	cmdQueue.enqueueWriteBuffer (bufRandom, false, 0, bufSize, RandomArray, []);
	cmdQueue.enqueueWriteBuffer( bufXYZ, false, 0, bufSize * 4, XYZArray, []);
	cmdQueue.finish();
}

function clCompute() {
	time0 = performance.now(); //timecheck 1
	cmdQueue.enqueueNDRangeKernel( kernel, globalWS.length, [], globalWS, LOCAL_WS, []);
	cmdQueue.finish();
	time1 = performance.now(); //timecheck 1
	elapsedTimesRaw[timeIDX] = time1-time0;
	if (timeIDX >= NUMMEASURES) {
		displayResults();
		return true;
	}
	timeIDX++;
	
	time0 = performance.now(); //timecheck 2
	cmdQueue.enqueueReadBuffer( bufXYZ, false, 0, bufSize * 4, XYZArray, []);
	cmdQueue.finish();
	time1 = performance.now(); //timecheck 2
	elapsedTimesRaw[timeIDX] = time1-time0;
	if (timeIDX >= NUMMEASURES) {
		displayResults();
		return true;
	}
	timeIDX++;
}

function loadKernel(id){
  var kernelElement = document.getElementById(id);
  var kernelSource = kernelElement.text;
  if (kernelElement.src != "") {
      var mHttpReq = new XMLHttpRequest();
      mHttpReq.open("GET", kernelElement.src, false);
      mHttpReq.send(null);
      kernelSource = mHttpReq.responseText;
  } 
  return kernelSource;
}